package de.lmu.mvs.lerngruppenfinder;

import java.util.ArrayList;
import java.util.List;

import com.eclipsesource.json.JsonArray;
import com.eclipsesource.json.JsonValue;

import de.lmu.mvs.lerngruppenfinder.interests.InterestNode;
import de.lmu.mvs.lerngruppenfinder.interests.InterestTree;
import de.lmu.mvs.lerngruppenfinder.utils.ApplicationController;
import de.lmu.mvs.lerngruppenfinder.utils.BaseActivity;
import de.lmu.mvs.lerngruppenfinder.utils.FileApi;
import de.lmu.mvs.lerngruppenfinder.utils.ServerConnector;
import de.lmu.mvs.lerngruppenfinder.utils.ServerConnector.ServerConnectorListener;
import de.lmu.mvs.lerngruppenfinder.utils.ServerConnector.ServerError;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.TransitionDrawable;
import android.os.Bundle;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

/**
 * View to select interests. There are two modes: singleMode = true | false. With singleMode true
 * y user can only select one child. With false the user can selct multiple children at once<br><br>
 * 
 * Start with onActivityResult and use request code {@link #REQUEST_INTEREST}. The chosen interest ids
 * are returned as comma separated string list
 * 
 * NOTE:
 * This Activity is build with the premise that there are two levels of interests.
 * First the fachgebiet and second the lehrveranstaltung. Some but not all methods
 * expect to have exactly two levels
 * 
 * @author chris
 * @date 29.06.2014
 *
 */
public class SetInterestActivity extends BaseActivity {

	private final static String TAG = SetInterestActivity.class.getSimpleName();

	public final static int REQUEST_INTEREST = 1337;

	/** tag for the interest string */
	public final static String INTEREST_RESULT = "interests";
	/** unique id for interest edit */
	public final static String INTERESTS_EDIT_ID = "interestsId";
	/** store interest ids here if the tree should use this settings */
	public final static String SELECTED_IDS = "selectedIds";

	public final static String MODE_SINGLE = "single_mode";

	private InterestTree mInterestTree;

	private int mRoot = 0;

	private InterestAdapter mAdapter;

	private TextView mTitleView;

	private ListView mList;

	private TextView mBtnSave;
	private TextView mBtnCancel;
	private ImageView mBtnBack;

	private Class callingActivity = null;

	/** in single mode there is only one child to select */
	private boolean mSingleMode = false;

	/** 
	 * unique id that helps keep track of what interests are edited.
	 * is simply returned when returning from the view
	 */
	private int mInterestEditId = 0;

	private List<Integer> mSelectedIds = null;
	
	private boolean mTransitionStateSave = false;

	private OnClickListener buttonListener = new OnClickListener() {

		@Override
		public void onClick(View v) {
			switch(v.getId()){
			case R.id.user_interaction_save_changes:
				saveInterests();
				break;
			case R.id.user_interaction_back:
				moveUp();
				break;
			case R.id.interest_title:
				moveUp();
				break;
			case R.id.user_interaction_cancel:
				saveInterests();
				break;
			}
		};
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		// hide actionbar
		getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
		getActionBar().hide();
		setContentView(R.layout.activity_set_interest);

		if(getIntent() != null){
			mSingleMode = getIntent().getBooleanExtra(MODE_SINGLE, false);
			mInterestEditId = getIntent().getIntExtra(INTERESTS_EDIT_ID, 0);

			/*
			 * We expect the array to contain ids that have exactly one root and
			 * zero to several child ids
			 */
			String tmp = getIntent().getStringExtra(SELECTED_IDS);
			if(tmp != null){
				String tmpArray[] = tmp.split(";");
				mSelectedIds = new ArrayList<Integer>(tmp.split(";").length);
				for (int i = 0; i < tmp.split(";").length; i++) {
					try {
						mSelectedIds.add(Integer.parseInt(tmpArray[i]));
					} catch(NumberFormatException e){
						// skip
					}
				}

				// when tree is initialized, compare tree with this list and set new root
			}
		}
		
		// set font type
		((TextView) findViewById(R.id.user_interaction_save_changes)).setTypeface(ApplicationController.getTypeFace());
		((TextView) findViewById(R.id.user_interaction_cancel)).setTypeface(ApplicationController.getTypeFace());
		
		if(getCallingActivity() != null){
			callingActivity = getCallingActivity().getClass();
		}

		mTitleView = (TextView) findViewById(R.id.interest_title);
		mList = (ListView) findViewById(R.id.interest_list);
		
		mBtnBack = (ImageView) findViewById(R.id.user_interaction_back);
		mBtnBack.setOnClickListener(buttonListener );
		mBtnSave = (TextView) findViewById(R.id.user_interaction_save_changes);
		mBtnSave.setOnClickListener(buttonListener);
		mBtnCancel = (TextView) findViewById(R.id.user_interaction_cancel);
		mBtnCancel.setOnClickListener(buttonListener);

		// create adapter and list (BEFORE loading data)
		mAdapter = new InterestAdapter(this, mSingleMode);
		mList.setAdapter(mAdapter);

		mList.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> adapter, View view, int position,
					long id) {
				updateInterestSelection((InterestNode)adapter.getItemAtPosition(position));
			}

		});

		// load interest tree
		JsonValue interestJson;
		Log.i(TAG, "Try loading interests from storage...");
		if((interestJson = FileApi.readJsonFromStorage("interests", this)) != null){
			if(interestJson.isArray()){
				mInterestTree = new InterestTree(interestJson.asArray());
				setSelectedRoot();
				updateList();
			}
		} else {
			// get list from server
			Log.i(TAG, "No files in storage available, try loading interests from server...");
			ServerConnector.getInterests(new ServerConnectorListener<JsonArray>() {

				@Override
				public void requestFinished(JsonArray json) {
					mInterestTree = new InterestTree(json);
					setSelectedRoot();
					updateList();
				}

				@Override
				public void requestError(ServerError error) {
					Log.e(TAG, error.getErrorMessage());
					Toast.makeText(getBaseContext(), "Error loading filters", Toast.LENGTH_LONG).show();
				}
			});
		}
	}

	/**
	 * If the calling activity passed some selected interest ids that 
	 * match the build tree with this list and set a new root node if 
	 * necessary
	 */
	private void setSelectedRoot(){
		if(mSelectedIds != null && mSelectedIds.size() > 0){
			mAdapter.setSelectedIds(mSelectedIds);
			for (Integer id : mSelectedIds) {
				if(mInterestTree.find(id) != null && mInterestTree.find(id).getChildren().size() > 0){
					transitionToSave();
					mRoot = id;
					updateInterestTitle();
					break;
				}
			}
		}
	}

	private void updateInterestSelection(InterestNode node) {
		if(node != null){
			if(node.getInterestId() > 0){
				transitionToSave();
			} else {
				transitionToCancel();
			}
			
			mRoot = node.getInterestId();
			updateList();
			updateInterestTitle();
		}
	}

	private void updateInterestTitle(){
		if(mRoot != 0){
			List<String> selectedInterests = new ArrayList<String>();

			SparseIntArray checkedItems = mAdapter.getSelectedItems();
			int key = 0;
			for(int i = 0; i < checkedItems.size(); i++) {
				key = checkedItems.keyAt(i);
				if(checkedItems.get(key) == 1){
					InterestNode checkedNode = mInterestTree.find(key);
					if(checkedNode != null){
						selectedInterests.add(checkedNode.getInterestName());
					}
				}
			}

			InterestNode node = mInterestTree.find(mRoot);
			while(node.getParent() != null){
				selectedInterests.add(node.getInterestName());
				node = node.getParent();
			}
			
			String title = "";
			if(mSingleMode){
				for (int i = selectedInterests.size()-1; i >= 0; i--) {
					title += selectedInterests.get(i);
					if(i > 0){
						title += " > ";
					}
				}
			} else {
				title = selectedInterests.get(selectedInterests.size()-1);
			}

			mTitleView.setText(title);
		} else {
			mTitleView.setText(getString(R.string.interest_choose_title));
		}
	}

	private void updateList() {
		if(mAdapter != null && mInterestTree != null){
			mAdapter.set(mInterestTree);

			/*
			 *  ugly switch: if selected ids are present that means its the first adapter update.
			 *  If this is the case we dont want to clear the selected ids in the adapter.
			 *  set list null to indicate the first update was done
			 */
			if(mSelectedIds != null){
				mAdapter.setRoot(mRoot, false);
				mSelectedIds = null;
			} else {
				mAdapter.setRoot(mRoot, true);
			}
			mAdapter.notifyDataSetChanged();
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.set_intereset, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		int id = item.getItemId();
		if (id == R.id.action_logout) {
	        	FileApi.deleteLoginCredentials();
	        	startActivity(new Intent(this, MainActivity.class));
	        	finish();
	        	return true;
		}
		return super.onOptionsItemSelected(item);
	}

	@Override
	public void onBackPressed() {
		moveUp();
	}

	private void moveUp(){
		if(mRoot == 0){
			super.onBackPressed();
		} else if(mInterestTree != null){
			updateInterestSelection(mInterestTree.find(mRoot).getParent());
		}
	}

	/**
	 * Send interest back to calling activity
	 */
	private void saveInterests(){
		Intent resultIntent = new Intent(this, callingActivity);
		InterestNode selectedNode = mInterestTree.find(mRoot);

		if(selectedNode != null){

			String interests = "";
			if(mSingleMode){
				interests += selectedNode.getInterestId();
			} else {
				SparseIntArray checkedItems = mAdapter.getSelectedItems();
				interests = selectedNode.getInterestId() + ((checkedItems.size() > 0) ? ";" : "");
				for(int i = 0, key = 0; i < checkedItems.size(); i++) {
					key = checkedItems.keyAt(i);
					if(checkedItems.get(key) == 1){
						InterestNode checkedNode = mInterestTree.find(key);
						if(checkedNode != null && i < checkedItems.size()-1){
							interests += checkedNode.getInterestId()+";";
						} else {
							interests += checkedNode.getInterestId()+"";
						}
					}
				}
			}

			resultIntent.putExtra(INTERESTS_EDIT_ID, mInterestEditId);
			resultIntent.putExtra(INTEREST_RESULT, interests);
			setResult(RESULT_OK, resultIntent);
		}
		finish();
	}

	private class InterestAdapter extends BaseAdapter {

		private SparseIntArray selectedIds = new SparseIntArray();

		private InterestTree mTree = null;

		private InterestNode root;

		private Context mContext;

		private int resourceParent = R.layout.interest_list_item_parent;
		private int resourceChild = R.layout.interest_list_item_checkbox;

		private final boolean singleMode;

		public InterestAdapter(Context context, boolean singleMode){
			super();
			this.singleMode = singleMode;
			mContext = context;
		}

		public void setRoot(int rootId, boolean clearSelection){
			if(clearSelection){
				selectedIds.clear();
				Log.d(TAG, "cleared selection");
			}

			if(mTree != null){
				root = mTree.find(rootId);
				if(root == null){
					root = mTree.root;
				}
			}
		}

		public void setSelectedIds(List<Integer> ids){
			for (Integer id : ids) {
				selectedIds.put(id, 1);
			}
		}

		public void set(InterestTree tree){
			if(tree != null){
				mTree = tree;
				root = mTree.root;
			}
		}

		public SparseIntArray getSelectedItems(){
			return selectedIds;
		}

		@Override
		public int getCount() {
			return (root != null) ? root.getChildren().size() : 0;
		}

		@Override
		public Object getItem(int position) {
			return (root.getChildren().size() > position) ? root.getChildren().get(position) : null;
		}

		@Override
		public long getItemId(int position) {
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
			InterestNode node = (InterestNode)getItem(position);

			if(node != null){

				if(node.getChildren().size() == 0 && !singleMode){ // has no children so display as checkbox
					convertView = inflater.inflate(resourceChild, parent, false);

					convertView.setTag(node.getInterestId());

					int bool = selectedIds.get(node.getInterestId());
					if(bool == 1){
						((CheckBox) convertView.findViewById(R.id.checkbox)).setChecked(true);
					}

					convertView.setOnClickListener(new OnClickListener() {

						@Override
						public void onClick(View v) {
							boolean checked = ((CheckBox) v.findViewById(R.id.checkbox)).isChecked();
							((CheckBox) v.findViewById(R.id.checkbox)).setChecked(!checked);
							selectedIds.put((Integer) v.getTag(), (!checked) ? 1 : 0);
							updateInterestTitle();
						}
					});

					// redundant but too lazy too make it beautiful
					((CheckBox) convertView.findViewById(R.id.checkbox)).setTag(node.getInterestId());
					((CheckBox) convertView.findViewById(R.id.checkbox))
					.setOnCheckedChangeListener(new OnCheckedChangeListener() {

						@Override
						public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
							int id = (Integer) buttonView.getTag();
							selectedIds.put(id, (isChecked) ? 1 : 0);
							updateInterestTitle();
						}
					});

				} else if(node.getChildren().size() == 0 && !singleMode){
					convertView = inflater.inflate(resourceChild, parent, false);
					convertView.findViewById(R.id.checkbox).setVisibility(View.GONE);

					convertView.setTag(node.getInterestId());
					convertView.setOnClickListener(new OnClickListener() {

						@Override
						public void onClick(View v) {
							boolean checked = ((CheckBox) v.findViewById(R.id.checkbox)).isChecked();
							((CheckBox) v.findViewById(R.id.checkbox)).setChecked(!checked);
							selectedIds.clear();
							selectedIds.put((Integer) v.getTag(), (!checked) ? 1 : 0);
							updateInterestTitle();
						}
					});
				} else { // has children so display a nice arrow
					convertView = inflater.inflate(resourceParent, parent, false);
					((TextView) convertView.findViewById(R.id.interest_parent_icon)).setTypeface(ApplicationController.getTypeFace());
				}

				TextView textViewItem = (TextView) convertView.findViewById(R.id.text1);
				textViewItem.setText(node.getInterestName());
			}
			return convertView;
		}
	}
	
	private void transitionToSave(){
		((TextView)findViewById(R.id.user_interaction_title)).setText(R.string.interest_save);
		findViewById(R.id.user_interaction_save_changes).setVisibility(View.VISIBLE);
		findViewById(R.id.user_interaction_cancel).setVisibility(View.GONE);

		if(!mTransitionStateSave){
			((TransitionDrawable) findViewById(R.id.user_interaction)
				.getBackground()).startTransition(250);
		}
		
		mTransitionStateSave = true;
	}
	
	private void transitionToCancel(){
		((TextView)findViewById(R.id.user_interaction_title)).setText(R.string.interest_choose_title);
		findViewById(R.id.user_interaction_save_changes).setVisibility(View.GONE);
		findViewById(R.id.user_interaction_cancel).setVisibility(View.VISIBLE);

		if(mTransitionStateSave){
			((TransitionDrawable) findViewById(R.id.user_interaction)
					.getBackground()).reverseTransition(250);
		}
		
		mTransitionStateSave = false;
	}
}
